/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.engine.cmd.swift;

import cn.easyplatform.EasyPlatformWithLabelKeyException;
import cn.easyplatform.contexts.RecordContext;
import cn.easyplatform.contexts.SwiftContext;
import cn.easyplatform.contexts.WorkflowContext;
import cn.easyplatform.dao.BizDao;
import cn.easyplatform.dos.FieldDo;
import cn.easyplatform.dos.Record;
import cn.easyplatform.entities.beans.table.TableBean;
import cn.easyplatform.entities.beans.table.TableField;
import cn.easyplatform.interceptor.AbstractCommand;
import cn.easyplatform.interceptor.CommandContext;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.request.GetSwiftRequestMessage;
import cn.easyplatform.messages.response.GetSwiftResponseMessage;
import cn.easyplatform.messages.vos.swift.LinkRowVo;
import cn.easyplatform.messages.vos.swift.LinkVo;
import cn.easyplatform.messages.vos.swift.TagFieldVo;
import cn.easyplatform.support.sql.SqlParser;
import cn.easyplatform.type.EntityType;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.util.MessageUtils;
import cn.easyplatform.util.RuntimeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;


/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class GetLinkCmd extends AbstractCommand<GetSwiftRequestMessage> {

	/**
	 * @param req
	 */
	public GetLinkCmd(GetSwiftRequestMessage req) {
		super(req);
	}

	@Override
	public IResponseMessage<?> execute(CommandContext cc) {
		WorkflowContext ctx = cc.getWorkflowContext();
		LinkVo lv = req.getBody();
		boolean isPreCmd = ctx.getParameterAsString("759").equals("Prev");
		SwiftContext sc = null;
		List<LinkRowVo> data = new ArrayList<LinkRowVo>();
		if (isPreCmd) {
			sc = ctx.getSwift(lv.getId());
			if (sc == null)
				return MessageUtils.swiftNotFound(lv.getId());
			Collection<RecordContext> list = sc.get(lv.getName());
			if (list != null) {
				for (RecordContext rc : list) {
					if (rc.getParameterAsChar("814") != 'D')
						data.add(getRow(rc));
				}
			}
			return new GetSwiftResponseMessage(data);
		} else if (!Strings.isBlank(lv.getFrom())) {
			int layer = NumberUtils.toInt(lv.getFrom());
			SwiftContext src = null;
			if (layer == 0)// 可能来自drop
				src = ctx.getSwift(lv.getFrom());
			else
				src = ctx.getSwift(layer, lv.getId());
			// if (src == null)
			// return MessageUtils.swiftNotFound(lv.getId());
			// if (!lv.isEditable())
			// return new SimpleResponseMessage(src.toText());
			// else {
			TableBean tb = cc.getEntity(lv.getEntity());
			if (tb == null)
				return MessageUtils.entityNotFound(EntityType.TABLE.getName(),
						lv.getEntity());
			if (Strings.isBlank(lv.getName())) {
				if (layer == 0)
					ctx.removeSwift(lv.getId());
				sc = ctx.setSwift(lv.getId(), tb, lv.isEditable());
				RecordContext rc = null;
				if (src != null)
					rc = sc.createRecord(src.get("", null).getData().clone());
				else
					rc = sc.createRecord(RuntimeUtils
							.createRecord(cc, tb, true));
				if (layer == 0)
					rc.setParameter("808", "onLoader");
				rc.setParameter("833", tb.getId());
				char c = rc.getParameterAsChar("814");
				if (c == 'C') {
					if (!Strings.isBlank(lv.getBefore())) {
						String code = RuntimeUtils.eval(cc, lv.getBefore(),
								ctx.getRecord(), rc);
						if (!code.equals("0000"))
							return MessageUtils.byErrorCode(cc, rc,
									ctx.getId(), code);
					}
				}
				if (!Strings.isBlank(lv.getAfter()))
					rc.setParameter("837", lv.getAfter());
				sc.appendRecord(lv.getParentName(), lv.getParentKeys(),
						lv.getName(), rc, false);
				data.add(getRow(rc));
			} else if (src != null) {
				sc = ctx.getSwift(lv.getId());
				RecordContext parent = sc.get(lv.getParentName(),
						lv.getParentKeys());
				int index = 1;
				Collection<RecordContext> list = src.get(lv.getName());
				if (list != null) {
					for (RecordContext r : list) {
						if (r.getParameterAsChar("814") != 'D') {
							RecordContext rc = sc.createRecord(r.getData()
									.clone());
							if (layer == 0)
								rc.setParameter("808", "onLoader");
							rc.setParameter("833", tb.getId());
							rc.setParameter("857", index);
							char c = rc.getParameterAsChar("814");
							if (c == 'C') {
								if (!Strings.isBlank(lv.getBefore())) {
									String code = RuntimeUtils.eval(cc,
											lv.getBefore(), parent, rc);
									if (!code.equals("0000"))
										return MessageUtils.byErrorCode(cc, rc,
												ctx.getId(), code);
								}
							}
							if (!Strings.isBlank(lv.getAfter()))
								rc.setParameter("837", lv.getAfter());
							sc.appendRecord(lv.getParentName(),
									lv.getParentKeys(), lv.getName(), rc, false);
							data.add(getRow(rc));
							index++;
						}
					}
				}
				if (layer > 0 && !Strings.isBlank(lv.getAutoCreateExpression())) {// 如果不为空
					Record record = RuntimeUtils.createRecord(cc, tb, true);
					RecordContext rc = sc.createRecord(record);
					rc.setParameter("833", tb.getId());
					rc.setParameter("857", index);
					Object result = RuntimeUtils.evalExpr(cc,
							lv.getAutoCreateExpression(), parent, rc);
					if (result != null
							&& result.toString().equalsIgnoreCase("true")) {
						if (!Strings.isBlank(lv.getBefore())) {
							String code = RuntimeUtils.eval(cc, lv.getBefore(),
									parent, rc);
							if (!code.equals("0000"))
								return MessageUtils.byErrorCode(cc, rc,
										ctx.getId(), code);
						}
						if (!Strings.isBlank(lv.getAfter()))
							rc.setParameter("837", lv.getAfter());
						sc.appendRecord(lv.getParentName(), lv.getParentKeys(),
								lv.getName(), rc, false);
						data.add(getRow(rc));
						sc.setEditable(true);
					}
				}
			}
			return new GetSwiftResponseMessage(data);
			// }
		} else if (!Strings.isBlank(lv.getQuery())) {
			TableBean tb = cc.getEntity(lv.getEntity());
			if (tb == null)
				return MessageUtils.entityNotFound(EntityType.TABLE.getName(),
						lv.getEntity());
			SqlParser<FieldDo> sp = RuntimeUtils.createSqlParser(FieldDo.class);
			String sql = sp.parse(lv.getQuery(), ctx.getRecord());
			if (Strings.isBlank(lv.getName())) {// root
				FieldDo[] record = cc.getBizDao()
						.selectOne(sql, sp.getParams());
				if (record == null) {
					String table = StringUtils.substringBetween(lv.getQuery()
							.toUpperCase(), "FROM", "WHERE");
					throw new EasyPlatformWithLabelKeyException(
							"table.record.not.found", table, sp.getParams()
									.toString());
				}
				Record rec = new Record();
				for (FieldDo fd : record)
					rec.set(fd);
				RecordContext src = ctx.createRecord(rec);
				RecordContext rc = null;
				sc = ctx.setSwift(lv.getId(), tb, lv.isEditable());
				rc = sc.createRecord(RuntimeUtils.createRecord(cc, tb, true));
				rc.setParameter("833", tb.getId());
				char c = rc.getParameterAsChar("814");
				if (c == 'C') {
					if (!Strings.isBlank(lv.getBefore())) {
						String code = RuntimeUtils.eval(cc, lv.getBefore(),
								src, rc);
						if (!code.equals("0000"))
							return MessageUtils.byErrorCode(cc, rc,
									ctx.getId(), code);
					}
				}
				if (!Strings.isBlank(lv.getAfter()))
					rc.setParameter("837", lv.getAfter());
				sc.appendRecord(lv.getParentName(), lv.getParentKeys(),
						lv.getName(), rc, false);
				data.add(getRow(rc));
			} else {
				List<FieldDo[]> records = cc.getBizDao().selectList(sql,
						sp.getParams());
				for (FieldDo[] record : records) {
					Record rec = new Record();
					for (FieldDo fd : record)
						rec.set(fd);
					RecordContext src = ctx.createRecord(rec);
					RecordContext rc = null;
					sc = ctx.getSwift(lv.getId());
					rc = sc.createRecord(RuntimeUtils
							.createRecord(cc, tb, true));
					rc.setParameter("833", tb.getId());
					char c = rc.getParameterAsChar("814");
					if (c == 'C') {
						if (!Strings.isBlank(lv.getBefore())) {
							String code = RuntimeUtils.eval(cc, lv.getBefore(),
									src, rc);
							if (!code.equals("0000"))
								return MessageUtils.byErrorCode(cc, rc,
										ctx.getId(), code);
						}
					}
					if (!Strings.isBlank(lv.getAfter()))
						rc.setParameter("837", lv.getAfter());
					sc.appendRecord(lv.getParentName(), lv.getParentKeys(),
							lv.getName(), rc, false);
					data.add(getRow(rc));
				}
			}
			return new GetSwiftResponseMessage(data);
		}
		TableBean tb = cc.getEntity(lv.getEntity());
		if (tb == null)
			return MessageUtils.entityNotFound(EntityType.TABLE.getName(),
					lv.getEntity());
		RecordContext parent = null;
		if (Strings.isBlank(lv.getName())) {
			sc = ctx.setSwift(lv.getId(), tb, lv.isEditable());
			parent = ctx.getRecord();
		} else {
			sc = ctx.getSwift(lv.getId());
			parent = sc.get(lv.getParentName(), lv.getParentKeys());
		}
		if (Strings.isBlank(lv.getName()) && Strings.isBlank(lv.getSel())
				&& parent.getParameter("833").equals(tb.getId())) {
			if (!Strings.isBlank(lv.getAfter()))
				parent.setParameter("837", lv.getAfter());
			parent.setParameter("814", "R");
			sc.appendRecord(lv.getParentName(), lv.getParentKeys(),
					lv.getName(), parent, false);
			data.add(getRow(parent));
		} else {
			BizDao dao = cc.getBizDao(tb.getSubType());
			SqlParser<FieldDo> sp = RuntimeUtils.createSqlParser(FieldDo.class);
			StringBuilder sb = new StringBuilder();
			Iterator<TableField> itr = tb.getFields().iterator();
			sb.append("select ");
			while (itr.hasNext()) {
				TableField tf = itr.next();
				sb.append(tf.getName());
				if (itr.hasNext())
					sb.append(",");
			}
			sb.append(" from ").append(tb.getId()).append(" where ")
					.append(lv.getSel());
			String sql = sp.parse(sb.toString(), parent);
			List<FieldDo[]> list = dao.selectList(sql, sp.getParams());
			int size = tb.getFields().size();
			for (FieldDo[] fields : list) {
				Record record = new Record();
				record.setKey(tb.getKey());
				for (int i = 0; i < size; i++) {
					TableField tf = tb.getFields().get(i);
					FieldDo fd = fields[i];
					fd.setDecimal(tf.getDecimal());
					fd.setAcc(tf.getAcc());
					fd.setLength(tf.getLength());
					fd.setDescription(tf.getDescription());
					record.set(fd);
				}
				RecordContext rc = sc.createRecord(record);
				rc.setParameter("833", tb.getId());
				rc.setParameter("814", "R");
				if (!Strings.isBlank(lv.getAfter()))
					rc.setParameter("837", lv.getAfter());
				sc.appendRecord(lv.getParentName(), lv.getParentKeys(),
						lv.getName(), rc, false);
				data.add(getRow(rc));
			}
		}
		return new GetSwiftResponseMessage(data);
	}

	private LinkRowVo getRow(RecordContext record) {
		LinkRowVo row = new LinkRowVo();
		List<TagFieldVo> tags = new ArrayList<TagFieldVo>();
		row.setData(tags);
		row.setKeys(record.getKeyValues());
		for (FieldDo field : record.getData().getData()) {
			if (isTag(field.getDescription())
					|| field.getDescription().endsWith("#")) {
				TagFieldVo tag = new TagFieldVo();
				tag.setLength(field.getLength());
				tag.setTagName(field.getDescription());
				tag.setName(field.getName());
				tag.setType(field.getType());
				tag.setValue(field.getValue());
				tags.add(tag);
			}
		}
		return row;
	}

	private boolean isTag(String name) {
		char[] cs = name.toCharArray();
		if (cs.length < 4) {
			for (int i = 0; i < cs.length; i++) {
				if (Strings.isChineseCharacter(cs[i]))
					return false;
			}
			return true;
		} else
			return false;
	}
}
